#include "bimoscontrol.h"
#include "View/qcustomplot.h"
#include "ui_bimoscontrol.h"
#include <QFileDialog>
#include <QDebug>

BimosControl::BimosControl(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::BimosControl)
{
    ui->setupUi(this);

    bHandler = new Connectivity();
    bView = new View(ui);
    saveDataTimer = new QTimer();

    setupGraphics();

    wizard = new NewProject();
    wizardCal = new Calibration();

    config = new Config();

    setupBimosBox();

}

BimosControl::~BimosControl()
{
    delete ui;
}

void BimosControl::setupGraphics() {
    connect(this, SIGNAL(sensorStateChanged(int,bool)), bView, SLOT(setSensorVisible(int,bool)));
    connect(bView->ui->clBtn_newProject,SIGNAL(clicked()),this,SLOT(showWizard()));
    connect(bView->ui->clBtn_continueProject, SIGNAL(clicked()), this , SLOT(loadConfig()));
    connect(bView->ui->clBtn_calibrate,SIGNAL(clicked()),this,SLOT(showCalibration()));

    int i = 0;
    for (i = 0; i < 14; i++){
        bView->btnEvacuate[i]->setEnabled(false);
        bView->btnPrepressure[i]->setEnabled(false);
    }

}

void BimosControl::setupBimosBox() {
    connect(bHandler->dataGrabber, SIGNAL(timeout()), bHandler->dataGrabber, SLOT(shot()));
    connect(bHandler->dataGrabber,SIGNAL(newValue(int,double)),this,SLOT(receiveNewSensorValue(int,double)));
    connect(bHandler->dataGrabber, SIGNAL(grabFinished()), bView, SLOT(redraw()));

    // connect absolute sensor to view
    connect(this,SIGNAL(newAbsoluteSensorValue(double)),bView,SLOT(receiveAbsolutePressureValue(double)));
    connect(this,SIGNAL(newTemperatureSensorValue(double)),bView,SLOT(receiveTemperature(double)));
}

void BimosControl::showWizard() {

    freezeProject();

    wizard->setConfig(config);
    wizard->exec();

/* DEBUG */
//    config->sensorList.clear();
//    BimosSensor* sensor;

//    sensor = new BimosSensor(5);
//    config->sensorList.insert(sensor->getOrdinal(), sensor);
//    sensor = new BimosSensor(6);
//    config->sensorList.insert(sensor->getOrdinal(), sensor);
//    config->setSampleTime(10);
/* DEBUG */

    startProject();
}


void BimosControl::startProject(){

    BimosSensorPressure* sensor;
    foreach (sensor, config->sensorList.values()) {
        bView->btnEvacuate[sensor->getOrdinal()]->setEnabled(true);
        bView->btnPrepressure[sensor->getOrdinal()]->setEnabled(true);
        connect(bView->btnEvacuate[sensor->getOrdinal()],SIGNAL(clicked()), this, SLOT(evacuateBottle()));
        connect(bView->btnPrepressure[sensor->getOrdinal()],SIGNAL(clicked()), this, SLOT(setPrepressureToBottle()));

        activeSensorList.insert(sensor->getOrdinal(), sensor);
        connect(sensor, SIGNAL(pressureChanged(BimosSensorPressure*)), bView, SLOT(draw(BimosSensorPressure*)));
        emit sensorStateChanged(sensor->getOrdinal(), true);
    }

    saveConfig();

    if (config->getSampleTime() > 0){
        bHandler->dataGrabber->setInterval(config->getSampleTime());
    }
    bHandler->start();
    startSavingData();

    qDebug() << "Start Project:" << config->getProjectName()
             << "with sample timer:" << config->getSampleTime()
             << "and log timer" << config->getLogTime();
}

void BimosControl::showCalibration() {
    wizardCal->setConfig(config);
    wizardCal->exec();
    saveConfig();
}


QMap<int, BimosSensorPressure*> *BimosControl::getSensorList(){
    tmpCloneList = activeSensorList;
    return &tmpCloneList;
}

bool BimosControl::setSensorState(bool newState, int ordinal){
    if (newState){
        if(inactiveSensorList.contains(ordinal)){
            emit sensorStateChanged(ordinal, newState);
            BimosSensorPressure *sensor = inactiveSensorList.take(ordinal);
            activeSensorList.insert(ordinal, sensor);
            connect(sensor, SIGNAL(pressureChanged(BimosSensorPressure*)), bView, SLOT(draw(BimosSensorPressure*)));
            return true;
        }
    } else {
        if(activeSensorList.contains(ordinal)){
            emit sensorStateChanged(ordinal, newState);
            BimosSensorPressure *sensor = activeSensorList.take(ordinal);
            inactiveSensorList.insert(ordinal, sensor);
            disconnect(sensor, 0, 0, 0);
            return true;
        }
    }
    return false;
}

void BimosControl::receiveNewSensorValue(int ordinal, double value) {  
    QMap<int, BimosSensorPressure*>::const_iterator i = activeSensorList.find(ordinal);
    // unique key
    if (i != activeSensorList.end() && i.key() == ordinal) {
        ((BimosSensorPressure*) i.value())->setVolt(value);
     }
    if (ordinal == SENSOR_ABSOLUTE_ORDINAL){
        config->absolutSensor->setVolt(value);
        emit newAbsoluteSensorValue(value/2.5);
    }
    if (ordinal == SENSOR_TEMPERATUR_ORDINAL){
        config->temperaturSensor->setVolt(value);
        emit newTemperatureSensorValue(value*16);
    }

}

void BimosControl::setPrepressureToBottle(){
    int ordinal = QObject::sender()->objectName().toInt();
    QMap<int, BimosSensorPressure*>::const_iterator i = activeSensorList.find(ordinal);
    BimosSensorPressure* sensor;
    // unique key
    if (i != activeSensorList.end() && i.key() == ordinal) {
        sensor = ((BimosSensorPressure*) i.value());
    }
    int ret = bView->showPrepressureDialog(sensor->getMeanPressure());
    if (ret == QMessageBox::Yes){
        sensor->setPrePressure(sensor->getMeanPressure());
    } else {
        bool ok;
        double d = QInputDialog::getDouble(this, tr("QInputDialog::getDouble()"), tr("Prepressure:"), 300, 0, 10000, 3, &ok);
        if (ok)
         sensor->setPrePressure(d);
    }
}


void BimosControl::evacuateBottle(){
    int ordinal = QObject::sender()->objectName().toInt();

    //TODO BADBOY!
    double actualAbsolutePressure = config->absolutSensor->getMeanVolt();


    BimosSensorPressure* sensor = activeSensorList.value(ordinal);

    //disconnect(sensor, SIGNAL(pressureChanged(BimosSensorPressure*)), bView, SLOT(draw(BimosSensorPressure*)));
    disconnect(bHandler->dataGrabber,SIGNAL(newValue(int,double)),this,SLOT(receiveNewSensorValue(int,double)));
    saveDataTimer->stop();

    qDebug() << "SensorMean before evacuation" << sensor->getVolt() << "AbsolutePressure" << actualAbsolutePressure;
    int ret = bView->showEvacuationDialog();
    if (ret == QMessageBox::Ok){
        sensor->setEvacuationOffset(actualAbsolutePressure);
    }
    connect(bHandler->dataGrabber,SIGNAL(newValue(int,double)),this,SLOT(receiveNewSensorValue(int,double)));
    saveDataTimer->start();
    qDebug() << "SensorMean after evacuation" << sensor->getVolt() << "AbsolutePressure" << actualAbsolutePressure;

}

void BimosControl::startSavingData() {

    connect(saveDataTimer,SIGNAL(timeout()),this,SLOT(saveDataToFile()));
    saveDataTimer->setInterval(config->getLogTime()*1000);
    saveDataTimer->start();
    file = new QFile();
    file->setFileName(config->getProjectName()+".dat");
    out = new QTextStream(file);
    file->open(QIODevice::WriteOnly | QIODevice::Text);
    *out << "timestamp" <<"\t"
         << "ordinal" << "\t"
         << "volt" << "\t"
         << "pressure" << "\t"
         << "meanVolt" << "\t"
         << "meanPressure" << "\t"
         << "gasYield" << "\t"
         << "steamPressure" << "\t"
         << "AbsolutePressure" << "\t"
         << "Temperature" << "\t"
         << "slope" << "\t"
         << "intercept" << "\t"
         << "offset" << endl;
    out->flush();
}

void BimosControl::saveDataToFile() {
    BimosSensorPressure* sensor;
    foreach (sensor, activeSensorList) {
        *out << QDateTime::currentMSecsSinceEpoch() << "\t"
             << sensor->getOrdinal() << "\t"
             << sensor->getVolt() << "\t"
             << sensor->getPressure() << "\t"
             << sensor->getMeanVolt() << "\t"
             << sensor->getMeanPressure() << "\t"
             << sensor->getGasYield(config->temperaturSensor->getSteamPressure(),30)<< "\t"
             << config->temperaturSensor->getTemperature() << "\t"
             << config->absolutSensor->getPressure() << "\t"
             << config->temperaturSensor->getTemperature() << "\t"
             << sensor->slope << "\t"
             << sensor->intercept << "\t"
             << sensor->getEvacuationOffset()
             << endl;
    }
    out->flush();
}

bool  BimosControl::saveConfig(){
    bool ret;

    QFile file("./" + config->getProjectName() + CONFIG_SUFFIX);
    ret = file.open(QIODevice::WriteOnly);
    if (ret){
        // we will serialize the data into the file
        QDataStream out(&file);
        out << *config;
        file.close();
        qDebug() << "Config written";
    }
    return ret;
}

void BimosControl::freezeProject()
{
    saveDataTimer->stop();
    // stop receiving values from BIMOS-Box
    bHandler->stop();
    // remove all sensors from the view
    disconnect(bView, SLOT(draw(BimosSensorPressure*)));
}

bool BimosControl::loadConfig() {
    bool ret;

    freezeProject();

    //TODO replace tr by this QSTRING
    //QString filter("Bimos File (*");
    //filter.append(CONFIG_SUFFIX);
    //filter.append(")");

    QString fileName = QFileDialog::getOpenFileName(this,
        tr("Open Bimos Configuration"), ".", tr("Bimos File (*.bimosConfig)"));

    QFile file(fileName);
    ret = file.open(QIODevice::ReadOnly);
    if (ret){
        QDataStream in(&file);
        in >> *config;
        file.close();
        qDebug() << "Config read";
        startProject();
    }
    return ret;
}
